from django.http import Http404
from rest_framework import status, mixins
from rest_framework.exceptions import NotFound
from rest_framework.viewsets import GenericViewSet

from utils.addons.responses import PageResponse, SuccessResponse


class BaseMixin:

    @property
    def qs(self):
        return getattr(self, 'get_queryset')()

    @property
    def model(self):
        return self.qs.model

    @property
    def verbose_name(self):
        return getattr(self.model, '_meta').verbose_name

    def get_instance(self):
        try:
            return getattr(self, 'get_object')()
        except (self.model.DoesNotExist, Http404):
            raise NotFound(f'{self.verbose_name}不存在')


class ListMixin(BaseMixin):
    """
    list 方法mixin类
    """

    def list(self, request, *args, **kwargs):
        queryset = getattr(self, 'filter_queryset')(self.qs)
        page = getattr(self, 'paginate_queryset')(queryset)
        if page is not None:
            serializer = getattr(self, 'get_serializer')(page, many=True)
            return getattr(self, 'get_paginated_response')(serializer.data)
        serializer = getattr(self, 'get_serializer')(queryset, many=True)
        return PageResponse(serializer.data)


# 逻辑删除
class LogicalDeleteMixin(BaseMixin):
    """
    逻辑删除mixin类
    """

    def destroy(self, request, *args, **kwargs):
        instance = self.get_instance()
        instance.is_deleted = True
        instance.save()
        return SuccessResponse(status=status.HTTP_204_NO_CONTENT)


# 逻辑删除ModelViewSet
class LogicalDeleteModelViewSet(mixins.CreateModelMixin,
                                mixins.RetrieveModelMixin,
                                mixins.UpdateModelMixin,
                                LogicalDeleteMixin,
                                ListMixin,
                                GenericViewSet):
    pass


class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           ListMixin,
                           GenericViewSet):
    """
    A viewset that provides default `list()` and `retrieve()` actions.
    """
    pass
